// Package stringset provides a simple API for sets of strings.
package stringset

import (
	"sort"
)

// A Set is represented as a map of string to bool so that expressions
// like set["apple"] are valid conditionals.
type Set map[string]bool

// NewSet constructs a new Set containing all of the given items.
func NewSet(strs ...string) Set {
	return make(Set).Add(strs...)
}

// Add adds the given elements to the set.  The updated set is
// returned to permit call chaining.
func (s Set) Add(strs ...string) Set {
	for _, str := range strs {
		s[str] = true
	}
	return s
}

// Copy creates a copy of the set without shared memory.
func (s Set) Copy() Set {
	s2 := NewSet()
	for str := range s {
		s2[str] = true
	}
	return s2
}

// Delete removes all of the given elements from the set, if present.
// The updated set is returned to permit call chaining.
func (s Set) Delete(strs ...string) Set {
	for _, str := range strs {
		delete(s, str)
	}
	return s
}

// Union mutates |s| to be the union of |s| and |s2|.  The updated set
// is returned to permit call chaining.
func (s Set) Union(s2 Set) Set {
	for str := range s2 {
		s[str] = true
	}
	return s
}

// Intersect mutates |s| to be the intersection of |s| and |s2|.  The
// updated set is returned to permit call chaining.
func (s Set) Intersect(s2 Set) Set {
	for str := range s {
		if !s2[str] {
			delete(s, str)
		}
	}
	return s
}

// Diff mutates |s| to be the difference of |s| and |s2|.  The updated
// set is returned to permit call chaining.
func (s Set) Diff(s2 Set) Set {
	for str := range s2 {
		delete(s, str)
	}
	return s
}

// OrderedSlice returns a slice containing all of the elements of |s|
// in ascending order.
func (s Set) OrderedSlice() []string {
	strs := s.Slice()
	sort.StringSlice(strs).Sort()
	return strs
}

// Slice returns a slice containing all of the elements of |s| in no
// particular order.
func (s Set) Slice() []string {
	strs := make([]string, 0, len(s))
	for str := range s {
		strs = append(strs, str)
	}
	return strs
}
